﻿using System;
using System.Collections.Generic;
using UnityEngine;

public struct CreatorTool
{
    public enum CreateType
    {
        Common,
        Scroll,
    }

    public CreateType createType;
    public int createIndex;
}

public static class CreatorToolEx
{
    public static CreatorTool GetTool(CreatorTool.CreateType createType)
    {
        return new CreatorTool() { createType = createType };
    }
}

public abstract class BaseScrollListCreator
{
    public ScrollRectEx tool;
    public List<RectTransform> activeList = new List<RectTransform>();
    public Stack<RectTransform> poolList = new Stack<RectTransform>();
    // 设置一个容许偏差
    public readonly float offsetRange = 10f;

    protected IScrollList scrollList;
    // 设置最后一个数据的索引
    public Action<int> m_lastItemChange;
    // 立刻刷新当前设置的控件
    public Action<RectTransform> m_refreshItemImmetiate;
    // 回收ui
    public Action<int, RectTransform> m_recycleItem;
    public virtual Vector2 Spacing { get; }

    public virtual void Init(ScrollRectEx tool, IScrollList scrollList)
    {
        this.tool = tool;
        this.scrollList = scrollList;
        Clear();
    }

    public abstract bool TryCreateNext(out RectTransform item, CreatorTool? tool);
    public abstract bool TryCreateBefore(out RectTransform item, CreatorTool? tool);

    public abstract bool TryInsertItem(int childIndex, out RectTransform item);
    public abstract bool TryGetItemByChildIndex(int childIndex, out RectTransform item);
    public abstract void TryRemoveItem(int childIndex);
    public abstract bool IsMoveNextDirection(Vector2 delta);
    public abstract bool IsMoveBeforeDirection(Vector2 delta);
    public abstract bool IsNeedCreateNext();
    public abstract bool IsNeedCreateBefore();
    public abstract void SetNormalizePosition(float normalize);
    public virtual void OnViewBoundsChange() { }

    public void UpdateActiveList()
    {
        activeList.Clear();
        poolList.Clear();
        for (int i = 0; i < tool.content.childCount; i++)
        {
            var child = tool.content.GetChild(i) as RectTransform;
            if (child.gameObject.activeInHierarchy)
                activeList.Add(child);
            else if (IsPoolItem(child))
                PushItem(child);
        }
    }

    public void Clear(bool isClear = false)
    {
        UpdateActiveList();
        for (int i = 0; i < activeList.Count; i++)
        {
            var item = activeList[i];
            if (isClear)
            {
                GameObject.Destroy(item.gameObject);
            }
            else
            {
                item.gameObject.SetActive(false);
                RecycleItem(i, item);
            }
        }
        activeList.Clear();
    }

    protected RectTransform PopItem()
    {
        RectTransform item = null;

        if (poolList.Count > 0)
            item = poolList.Pop();
        else
            item = GameObject.Instantiate(tool.defaultItem.gameObject, tool.content).transform as RectTransform;

        item.gameObject.SetActive(true);
        return item;
    }

    protected void RecycleItem(int itemIndex, RectTransform item)
    {
        m_recycleItem(itemIndex, item);
        PushItem(item);
    }

    protected void PushItem(RectTransform item)
    {
        item.gameObject.SetActive(false);
        poolList.Push(item);
    }

    private bool IsPoolItem(RectTransform item)
    {
        if (item.gameObject.activeSelf)
            return false;

        // 默认结尾(clone)
        if (item.name.Length > 0 && item.name[item.name.Length - 1] == ')')
            return true;

        return false;
    }

    protected int GetUnactivatedCount(int activeIndex)
    {
        var unactivatedCount = 0;
        var curActiveIndex = -1;

        for (int i = 0; i < tool.content.childCount; i++)
        {
            var child = tool.content.GetChild(i);

            if (!child.gameObject.activeSelf)
                unactivatedCount++;
            else
                curActiveIndex++;

            if (curActiveIndex >= activeIndex)
                break;
        }

        return unactivatedCount;
    }
}